// 设计相关服务
package services

import (
	"bsm/config"
	"bsm/daos"
	"bsm/logger"
	"bsm/models"
	"errors"
	"fmt"
	"strconv"
	"strings"
	"time"

	"github.com/google/uuid"
)

type DesignService interface {
	// 获取组织列表
	GetOrgList() ([]models.Org, error)

	GetDesignLabor(normcode string) ([]models.DesignNorm, error)       // 获取人工定额规范
	GetDesignMaterial(mtlcode string) ([]models.DesignMaterial, error) // 获取设计材料规范

	CreateProject(project *models.ProjectBase) (string, error)            // 创建项目
	CreateProjectFrom(designCode string, designer string) (string, error) // 从已有项目创建项目
	// 获取项目立项信息
	GetProjectBase(designCode string) (*models.ProjectBase, error) // 获取项目立项信息
	// 更新项目立项信息
	UpdateProjectBase(project *models.ProjectBase) error // 更新项目立项信息(折扣、税率及安全生产费率不变)

	SaveProjectTable(data models.ProjectTable) error                                                // 保存项目设计数据
	GetProjectResume(pcode string, dtype int) (models.WebProjectResume, error)                      // 获取项目摘要
	GetMaterialPrice(materialprices []models.MaterialPrice, orgcode string, dtype int) (int, error) // 获取材料单价（设计期 结算期）
	GetProjectList(orgcode string, dtype int) ([]models.WebProjectList, error)                      // 获取项目列表
	LoadProjectLabor(pcode string, dtype int) ([]models.WebProjectLaborItem, error)                 // 加载项目人工费条目
	LoadProjectMaterial(pcode string, dtype int) ([]models.WebProjectMaterialItem, error)           // 加载项目材料条目
	LoadProjectOtherFee(pcode string, dtype int) (models.WebProjectOtherFee, error)                 // 加载项目其他费用条目

	GetNormConversion(normcode string) ([]models.WebProjectNormConversionItem, error)                 // 获取定额转换系数
	SaveProjectLabor(dcode string, dtype int, data []models.LaborItem) error                          // 保存项目设计人工数据
	SaveProjectMaterial(dcode string, dtype int, data []models.MaterialItem, refreshPrice bool) error // 保存项目设计材料数据
	SaveProjectOtherFee(dcode string, atype int, data []models.OtherFeeItem) error                    // 保存项目其他费用数据

	NewTab2(input InputDataTab2) *Calculator
	GetConstructionCost(designcode string, dtype int) (float64, error)
	NewTab5(designcode string, dtype int) *OtherConstructionCost

	GetProjectReviewer(orgCode string) ([]models.ProjectReviewer, error)
	SetProjectFiled(pcode string, state int) error // 项目存档

	DeleteProject(pcode string, dtype int) error // 删除项目设计数据

}

type designServiceImpl struct {
	designDao daos.DesignDao
	userDao   daos.UserDao
	scmDao    daos.ScmDao
}

func NewDesignService(designDao daos.DesignDao, pmsDao daos.UserDao, scmDao daos.ScmDao) DesignService {

	return &designServiceImpl{
		designDao: designDao,
		userDao:   pmsDao,
		scmDao:    scmDao,
	}
}

// 获取组织列表
func (s *designServiceImpl) GetOrgList() ([]models.Org, error) {
	orgList, err := s.designDao.GetOrgList()
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "designServiceImpl-GetOrgList",
		}).Warn("获取组织列表失败")
		return nil, fmt.Errorf("获取组织列表失败: %w", err)
	}
	return orgList, nil
}

// GetDesignLabor 获取人工定额规范
func (s *designServiceImpl) GetDesignLabor(normcode string) ([]models.DesignNorm, error) {
	norms, err := s.designDao.GetDesignNormByCode(normcode)
	if err != nil {
		// Service层只记录业务上下文，不重复DAO层的技术错误
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "designServiceImpl-GetDesignLabor",
			"normcode":  normcode,
		}).Warn("获取人工定额规范失败")
		return nil, fmt.Errorf("获取人工定额规范失败: %w", err)
	}

	logger.WithFields(map[string]interface{}{
		"layer":       "service",
		"operation":   "designServiceImpl-GetDesignLabor",
		"normcode":    normcode,
		"norms_count": len(norms),
	}).Debug("获取人工定额规范成功")

	return norms, nil
}

// 获取定额转换系数
func (s *designServiceImpl) GetNormConversion(normcode string) ([]models.WebProjectNormConversionItem, error) {
	items, err := s.designDao.GetNormConversion(normcode)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "designServiceImpl-GetNormConversion",
			"normcode":  normcode,
		}).Warn("获取定额转换系数失败")
		return nil, fmt.Errorf("获取定额转换系数失败: %w", err)
	}
	return items, nil
}

// GetDesignMaterial 获取设计材料
func (s *designServiceImpl) GetDesignMaterial(mtlcode string) ([]models.DesignMaterial, error) {
	materials, err := s.designDao.GetDesignMaterialByCode(mtlcode)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "designServiceImpl-GetDesignMaterial",
			"mtlcode":   mtlcode,
		}).Warn("获取设计材料失败")
		return nil, fmt.Errorf("获取设计材料失败: %w", err)
	}
	return materials, nil
}

// CreateProject 创建项目
func (s *designServiceImpl) CreateProject(project *models.ProjectBase) (string, error) {
	if project == nil {
		return "", errors.New("项目信息不能为空")
	}
	code, err := s.genDesignCode(project.OrgCode)
	if err != nil {
		return "", fmt.Errorf("生成项目设计编号失败: %w", err)
	}
	project.DesignCode = code

	err = s.designDao.InTransaction(func() error {
		if err := s.designDao.SetProjectBase(project); err != nil {
			return fmt.Errorf("保存项目基本信息失败: %w", err)
		}

		cfg := config.Get().DesignConfig
		if err := s.designDao.SetProjectConfig(models.ProjectDesignConfig{
			DesignCode:    project.DesignCode,
			DiscountRates: cfg.DiscountRates,
			SafeRate:      cfg.SafeRate,
			VatRate:       cfg.VatRate,
		}); err != nil {
			return fmt.Errorf("保存项目设计配置失败: %w", err)
		}
		err = s.designDao.UpdateDesignTime(project.DesignCode, models.ProjectState_Budget)
		if err != nil {
			return fmt.Errorf("更新项目设计预算时间戳失败: %w", err)
		}
		return nil
	})

	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":        "service",
			"operation":    "designServiceImpl-CreateProject",
			"project_name": project.Name,
			"org_code":     project.OrgCode,
		}).Error("创建项目失败")
	} else {
		// 记录重要的成功操作
		logger.WithFields(map[string]interface{}{
			"layer":        "service",
			"operation":    "designServiceImpl-CreateProject",
			"design_code":  project.DesignCode,
			"project_name": project.Name,
			"org_code":     project.OrgCode,
		}).Info("创建项目成功")
	}

	return project.DesignCode, err
}

// CreateProjectFrom 从已有项目创建项目
func (s *designServiceImpl) CreateProjectFrom(designCode string, designer string) (string, error) {
	project, err := s.designDao.GetProjectBase(designCode)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-CreateProjectFrom",
			"design_code": designCode,
		}).Warn("获取源项目信息失败")
		return "", fmt.Errorf("获取源项目信息失败: %w", err)
	}
	if project == nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-CreateProjectFrom",
			"design_code": designCode,
		}).Warn("源项目不存在")
		return "", fmt.Errorf("源项目不存在: %s", designCode)
	}
	project.DesignCode = ""
	project.Name = "参考立项（" + project.Name + "）"
	project.ProjectOverview = "参考立项（" + project.ProjectOverview + "）"
	project.Designer = designer
	user, err := s.userDao.GetUserByUserID(designer)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-CreateProjectFrom",
			"design_code": designCode,
		}).Warn("获取当前用户信息失败")
		return "", fmt.Errorf("获取当前用户信息失败: %w", err)
	}
	project.OrgCode = user.OrgCode

	newcode, err := s.CreateProject(project)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":              "service",
			"operation":          "designServiceImpl-CreateProjectFrom",
			"source_design_code": designCode,
			"new_designer":       designer,
			"new_org_code":       project.OrgCode,
		}).Error("从已有项目创建新项目失败")
		return "", fmt.Errorf("从已有项目创建新项目失败: %w", err)
	}

	// 复制人工数据
	oldLabor, err := s.LoadProjectLabor(designCode, models.DesignType_Budget)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-CreateProjectFrom",
			"design_code": designCode,
		}).Warn("加载源项目人工数据失败")
		return "", fmt.Errorf("加载源项目人工数据失败: %w", err)
	}
	var newLabor []models.LaborItem
	for _, item := range oldLabor {
		var conversions []models.NormConversionItem
		for _, conv := range item.Conversions {
			conversions = append(conversions, models.NormConversionItem{
				NciID: conv.ID,
			})
		}
		var machines []models.MachineItem
		for _, conv := range item.Machines {
			machines = append(machines, models.MachineItem{
				MachID:   conv.ID,
				Quantity: conv.Quantity,
				Remark:   conv.Remark,
			})
		}
		var instruments []models.InstrumentItem
		for _, conv := range item.Instruments {
			instruments = append(instruments, models.InstrumentItem{
				InstID:   conv.ID,
				Quantity: conv.Quantity,
				Remark:   conv.Remark,
			})
		}
		newLabor = append(newLabor, models.LaborItem{
			DesignCode:  newcode,
			DesignType:  1,
			Code:        item.NormItem.NormCode,
			Quantity:    item.Quantity,
			Remark:      item.Remark,
			Conversions: conversions,
			Machines:    machines,
			Instruments: instruments,
		})
	}
	s.SaveProjectLabor(newcode, models.DesignType_Budget, newLabor)

	// 复制材料数据
	oldMaterial, err := s.LoadProjectMaterial(designCode, models.DesignType_Budget)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-CreateProjectFrom",
			"design_code": designCode,
		}).Warn("加载源项目材料数据失败")
		return "", fmt.Errorf("加载源项目材料数据失败: %w", err)
	}
	var newMaterial []models.MaterialItem
	for _, item := range oldMaterial {
		newMaterial = append(newMaterial, models.MaterialItem{
			DesignCode: newcode,
			DesignType: 1,
			Code:       item.Code,
			Name:       item.Name,
			Price:      item.Price,
			Quantity:   item.Quantity,
			Remark:     item.Remark,
		})
	}
	err = s.SaveProjectMaterial(newcode, models.DesignType_Budget, newMaterial, true)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":           "service",
			"operation":       "designServiceImpl-CreateProjectFrom",
			"new_design_code": newcode,
		}).Error("保存新项目材料数据失败")
		return "", fmt.Errorf("保存新项目材料数据失败: %w", err)
	}

	// 复制其他费用数据
	oldOther, err := s.LoadProjectOtherFee(designCode, models.DesignType_Budget)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-CreateProjectFrom",
			"design_code": designCode,
		}).Warn("加载源项目其他费用失败")
		return "", fmt.Errorf("加载源项目其他费用失败: %w", err)
	}
	s.SaveProjectOtherFee(newcode, models.DesignType_Budget, oldOther.OtherFee)

	logger.WithFields(map[string]interface{}{
		"layer":              "service",
		"operation":          "designServiceImpl-CreateProjectFrom",
		"source_design_code": designCode,
		"new_design_code":    newcode,
		"designer":           designer,
		"org_code":           project.OrgCode,
		"labor_items":        len(newLabor),
		"material_items":     len(newMaterial),
	}).Info("从已有项目创建新项目成功")

	return newcode, nil
}

// GetProjectBase 获取项目立项信息
func (s *designServiceImpl) GetProjectBase(designCode string) (*models.ProjectBase, error) {
	project, err := s.designDao.GetProjectBase(designCode)

	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-GetProjectBase",
			"design_code": designCode,
		}).Warn("获取项目基础信息失败")
		return nil, fmt.Errorf("获取项目基础信息失败: %w", err)
	}

	if project != nil && project.ApprovalCode == "" {
		project.ApprovalCode, err = s.scmDao.GetApprovalCodeByName(project.Name)
		if err != nil {
			// 非关键错误，使用Debug级别
			logger.WithFields(map[string]interface{}{
				"layer":        "service",
				"operation":    "designServiceImpl-GetProjectBase",
				"project_name": project.Name,
			}).Debug("获取审批编码失败，使用空值")
		}
	}

	if project != nil {
		config, err := s.designDao.GetProjectConfig(designCode)
		if err != nil {
			logger.WithFields(map[string]interface{}{
				"layer":       "service",
				"operation":   "designServiceImpl-GetProjectBase",
				"design_code": designCode,
			}).Warn("获取项目配置失败")
			return nil, fmt.Errorf("获取项目配置失败: %w", err)
		}
		if config == nil {
			project.DesignConfig = models.ProjectDesignConfig{}
		} else {
			project.DesignConfig = *config
		}
	}

	return project, nil
}

// UpdateProjectBase 更新项目立项信息
func (s *designServiceImpl) UpdateProjectBase(project *models.ProjectBase) error {
	if project == nil {
		return errors.New("项目基础信息不能为空")
	}
	if project.DesignCode == "" {
		return errors.New("设计编号不能为空")
	}

	err := s.designDao.InTransaction(func() error {
		if err := s.designDao.SetProjectBase(project); err != nil {
			return fmt.Errorf("更新项目基础信息失败: %w", err)
		}
		err := s.designDao.UpdateDesignTime(project.DesignCode, models.ProjectState_Budget)
		if err != nil {
			return fmt.Errorf("更新项目设计时间失败: %w", err)
		}
		return nil
	})

	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":        "service",
			"operation":    "designServiceImpl-UpdateProjectBase",
			"design_code":  project.DesignCode,
			"project_name": project.Name,
		}).Error("更新项目立项信息失败")
	} else {
		logger.WithFields(map[string]interface{}{
			"layer":        "service",
			"operation":    "designServiceImpl-UpdateProjectBase",
			"design_code":  project.DesignCode,
			"project_name": project.Name,
		}).Info("更新项目立项信息成功")
	}

	return err
}

// genDesignCode 生成项目设计编号
func (s *designServiceImpl) genDesignCode(orgcode string) (string, error) {
	prefix, err := s.getOrgPrefix(orgcode)
	if err != nil {
		return "", err
	}

	seq, err := s.generateSequence(prefix)
	if err != nil {
		return "", err
	}

	designCode := prefix + seq

	logger.WithFields(map[string]interface{}{
		"layer":       "service",
		"operation":   "designServiceImpl-genDesignCode",
		"org_code":    orgcode,
		"prefix":      prefix,
		"sequence":    seq,
		"design_code": designCode,
	}).Debug("生成项目设计编号")

	return designCode, nil
}

// getOwnerPrefix 获取项目设计编号前缀(建设单位前缀)
func (s *designServiceImpl) getOrgPrefix(orgcode string) (string, error) {
	org, err := s.userDao.GetOrgByCode(orgcode)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "designServiceImpl-getOrgPrefix",
			"org_code":  orgcode,
		}).Warn("获取建设单位信息失败")
		return "", fmt.Errorf("获取建设单位信息失败: %w", err)
	}
	return org.Prefix + time.Now().Format("20060102") + "-", nil
}

func (s *designServiceImpl) generateSequence(prefix string) (string, error) {
	var id string
	pos := strconv.Itoa(len(prefix) + 1)

	if err := s.designDao.GetMaxProjectCode(&id, prefix, pos); err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "designServiceImpl-generateSequence",
			"prefix":    prefix,
			"pos":       pos,
		}).Warn("获取最大项目编码失败")
		return "", fmt.Errorf("获取最大项目编码失败: %w", err)
	}

	if strings.TrimSpace(id) == "" {
		return "001", nil
	}

	n, err := strconv.Atoi(id)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "designServiceImpl-generateSequence",
			"id":        id,
		}).Warn("解析序列号失败")
		return "", fmt.Errorf("解析序列号失败: %w", err)
	}

	return fmt.Sprintf("%03d", n+1), nil
}

// SaveProjectLabor 保存项目设计人工数据
func (s *designServiceImpl) SaveProjectLabor(dcode string, dtype int, data []models.LaborItem) error {
	err := s.designDao.InTransaction(func() error {
		if len(data) == 0 {
			return s.designDao.ClearProjectLabors(dcode, dtype)
		}
		// 使用索引来修改原始切片元素
		for i := range data {
			if data[i].LID == "" {
				data[i].LID = uuid.New().String()
			}
		}

		var err error
		// err = s.designDao.SetLaborMachines(data)
		// if err != nil {
		// 	return fmt.Errorf("更新项目机器数据失败: %w", err)
		// }
		// err = s.designDao.SetLaborInstruments(data)
		// if err != nil {
		// 	return fmt.Errorf("更新项目仪器数据失败: %w", err)
		// }

		err = s.designDao.SetProjectLabors(dcode, dtype, data)
		if err != nil {
			return fmt.Errorf("保存项目人工数据失败: %w", err)
		}
		err = s.designDao.UpdateDesignTime(dcode, dtype)
		if err != nil {
			return fmt.Errorf("更新项目设计时间失败: %w", err)
		}
		return nil
	})

	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-SaveProjectLabor",
			"design_code": dcode,
			"design_type": dtype,
			"items_count": len(data),
		}).Error("保存项目人工数据失败")
	} else {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-SaveProjectLabor",
			"design_code": dcode,
			"design_type": dtype,
			"items_count": len(data),
		}).Info("保存项目人工数据成功")
	}

	return err
}

// SaveProjectMaterial 保存项目设计材料数据
func (s *designServiceImpl) SaveProjectMaterial(dcode string, designtype int, data []models.MaterialItem, refreshPrice bool) error {

	err := s.designDao.InTransaction(func() error {
		if len(data) == 0 {
			return s.designDao.ClearProjectMaterials(dcode, designtype)
		}
		if refreshPrice {
			// 转换为材料价格格式
			materialPrices := make([]models.MaterialPrice, 0, len(data))
			for _, item := range data {
				materialPrices = append(materialPrices, models.MaterialPrice{
					MaterialCode: item.Code,
					Price:        item.Price,
				})
			}
			baselite, err := s.designDao.GetProjectBaseLite(dcode)
			if err != nil {
				return fmt.Errorf("获取项目立项信息失败: %w", err)
			}
			orgcode := baselite.OrgCode
			s.GetMaterialPrice(materialPrices, orgcode, designtype)
			if _, err := s.scmDao.GetMaterialPurchasePrice(materialPrices); err != nil {
				return fmt.Errorf("获取材料采购价格失败: %w", err)
			}

			datalen := len(data)
			for i := 0; i < datalen; i++ {
				for _, price := range materialPrices {
					if data[i].Code == price.MaterialCode {
						data[i].Price = price.Price
					}
				}
			}
		}
		err := s.designDao.SetProjectMaterials(dcode, designtype, data)
		if err != nil {
			return fmt.Errorf("保存项目材料数据失败: %w", err)
		}
		err = s.designDao.UpdateDesignTime(dcode, designtype)
		if err != nil {
			return fmt.Errorf("更新项目设计时间失败: %w", err)
		}
		return nil
	})
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-SaveProjectMaterial",
			"design_code": dcode,
			"design_type": designtype,
			"items_count": len(data),
		}).Error("保存项目材料数据失败")
	} else {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-SaveProjectMaterial",
			"design_code": dcode,
			"design_type": designtype,
			"items_count": len(data),
		}).Info("保存项目材料数据成功")
	}
	return err
}

// SaveProjectTable 保存项目设计数据
func (s *designServiceImpl) SaveProjectTable(data models.ProjectTable) error {

	if data.DesignCode == "" {
		return errors.New("项目编号不能为空")
	}

	dcode := data.DesignCode
	dtype := data.DesignType

	err := s.designDao.InTransaction(func() error {

		var err error

		// 先清除旧数据
		if err = s.designDao.ClearProjectLabors(dcode, dtype); err != nil {
			logger.WithFields(map[string]interface{}{
				"layer":       "service",
				"operation":   "designServiceImpl-SaveProjectTable",
				"design_code": dcode,
				"design_type": dtype,
			}).Error("清除项目人工数据失败")
			return fmt.Errorf("清除项目人工数据失败: %w", err)
		}

		// 保存人工定额数据

		if len(data.LaborTable) > 0 {

			var labors []models.LaborItem
			for _, item := range data.LaborTable {
				item.LID = uuid.New().String()

				labors = append(labors, models.LaborItem{
					LID:        item.LID,
					DesignCode: dcode,
					DesignType: dtype,
					Code:       item.Code,
					Quantity:   item.Quantity,
					Remark:     item.Remark,
				})

				// 保存人工定额调整数据
				// 这里要注意：如果存在调整，相应的机械、仪表和材料都要考虑是否存在调整系数
				if err = s.designDao.SetProjectConversions(item.LID, item.Conversions); err != nil {
					logger.WithFields(map[string]interface{}{
						"layer":       "service",
						"operation":   "designServiceImpl-SaveProjectTable",
						"design_code": dcode,
						"design_type": dtype,
					}).Error("保存项目转换调整数据失败")
				}

				// 保存机械台班数据
				if err = s.designDao.SetProjectMachines(item.LID, item.Machines); err != nil {
					logger.WithFields(map[string]interface{}{
						"layer":       "service",
						"operation":   "designServiceImpl-SaveProjectTable",
						"design_code": dcode,
						"design_type": dtype,
					}).Error("保存项目机械台班数据失败")
				}
				// 保存仪器仪表数据
				if err = s.designDao.SetProjectInstruments(item.LID, item.Instruments); err != nil {
					logger.WithFields(map[string]interface{}{
						"layer":       "service",
						"operation":   "designServiceImpl-SaveProjectTable",
						"design_code": dcode,
						"design_type": dtype,
					}).Error("保存项目仪器仪表数据失败")
				}
			}

			if err = s.designDao.SetProjectLabors(dcode, dtype, labors); err != nil {
				logger.WithFields(map[string]interface{}{
					"layer":       "service",
					"operation":   "designServiceImpl-SaveProjectTable",
					"design_code": dcode,
					"design_type": dtype,
				}).Error("保存项目人工数据失败")
				return fmt.Errorf("保存项目人工数据失败: %w", err)
			}
		}

		if err = s.designDao.SetProjectMaterials(dcode, dtype, data.MaterialTable); err != nil {
			logger.WithFields(map[string]interface{}{
				"layer":       "service",
				"operation":   "designServiceImpl-SaveProjectTable",
				"design_code": dcode,
				"design_type": dtype,
			}).Error("保存项目材料数据失败")
			return fmt.Errorf("保存项目材料数据失败: %w", err)
		}
		return nil

	})

	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-SaveProjectTable",
			"design_code": dcode,
			"design_type": dtype,
		}).Error("保存项目设计表格失败")

	} else {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-SaveProjectTable",
			"design_code": dcode,
			"design_type": dtype,
		}).Info("保存项目设计表格成功")
	}
	return err
}

// GetProjectResume 获取项目摘要
func (s *designServiceImpl) GetProjectResume(pcode string, dtype int) (models.WebProjectResume, error) {
	var err error

	var resume models.WebProjectResume
	state, err := s.designDao.GetProjectState(pcode)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-GetProjectResume",
			"design_code": pcode,
			"design_type": dtype,
		}).Error("获取项目存档信息失败")
		return models.WebProjectResume{}, fmt.Errorf("获取项目存档信息失败: %w", err)
	}

	resume.Filed = state > dtype

	prj, err := s.designDao.GetProjectBaseLite(pcode)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-GetProjectResume",
			"design_code": pcode,
			"design_type": dtype,
		}).Error("获取项目简介失败")
		return models.WebProjectResume{}, fmt.Errorf("获取项目简介失败: %w", err)
	}

	if prj.DesignCode == "" {
		return resume, errors.New("项目编号不能为空")
	}

	resume.ID = prj.ID
	resume.DesignType = dtype
	resume.DesignCode = prj.DesignCode
	resume.Name = prj.Name
	resume.ProjectOverview = prj.ProjectOverview
	resume.Mechanic, resume.General, err = s.calcLaborCost(pcode, dtype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-GetProjectResume",
			"design_code": prj.DesignCode,
			"design_type": dtype,
		}).Error("获取项目人工成本失败")
	}

	resume.Machine, err = s.calcMachineCost(prj.DesignCode, dtype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-GetProjectResume",
			"design_code": prj.DesignCode,
			"design_type": dtype,
		}).Error("获取项目机械成本失败")
	}
	resume.Instrument, err = s.calcInstrumentCost(prj.DesignCode, dtype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-GetProjectResume",
			"design_code": prj.DesignCode,
			"design_type": dtype,
		}).Error("获取项目仪器仪表成本失败")
	}

	resume.MaterialAmount, resume.MaterialTypeCount, err = s.designDao.GetMaterialCost(prj.DesignCode, dtype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-GetProjectResume",
			"design_code": prj.DesignCode,
			"design_type": dtype,
		}).Error("获取项目材料成本失败")
	}

	t4 := models.SummaryTable4{
		MaterialSupply: resume.MaterialAmount,
	}

	tab2input := InputDataTab2{
		MechanicDays:     resume.Mechanic,
		GeneralDays:      resume.General,
		MachineCost:      resume.Machine,
		InstrumentCost:   resume.Instrument,
		MainMaterialCost: resume.MaterialAmount,
	}

	// log.Printf("tab2input: %+v", tab2input)

	// 创建计算器
	tab2 := s.NewTab2(tab2input)

	// 计算（自动按依赖顺序）
	if err := tab2.CalculateTab2(); err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-GetProjectResume",
			"design_code": prj.DesignCode,
			"design_type": dtype,
		}).Error("计算项目表二数据失败")
		return resume, fmt.Errorf("计算项目表二数据失败: %w", err)
	}

	st2 := models.SummaryTable2{
		ConstructionCost: tab2.items["exclusive_tax_cost"].Value,
		LaborCost:        tab2.items["labor_cost"].Value,
		MachineCost:      tab2.items["machine_cost"].Value,
		InstrumentCost:   tab2.items["instrument_cost"].Value,
		MeasureFee:       tab2.items["measure_cost"].Value,
		ManagementFee:    tab2.items["management_fee"].Value,
		Profit:           tab2.items["profit"].Value,
		Tax:              tab2.items["tax"].Value,
	}

	tab5 := s.NewTab5(pcode, dtype)

	tab5.CalculateTab5(st2.ConstructionCost)
	t5 := models.SummaryTable5{
		OtherFee: tab5.Totals["excluding_tax"],
		OtherTax: tab5.Totals["vat"],
	}

	resume.OtherMoney = tab5.Items["other_total"].IncludingTax

	rates := config.Get().DesignConfig.DiscountRates

	// --- 2. 计算下浮费用 ---
	discountDetails := make(map[string]float64)
	discountDetails["人工费"] = st2.LaborCost * (1 - rates.DiscountLabor)
	discountDetails["机械费"] = st2.MachineCost * (1 - rates.DiscountMachine)
	discountDetails["仪表费"] = st2.InstrumentCost * (1 - rates.DiscountInstrument)
	discountDetails["措施费"] = (st2.MeasureFee - st2.LaborCost*0.015) * (1 - rates.DiscountMeasure) // 文明施工费不参与打折
	discountDetails["企业管理费"] = st2.ManagementFee * (1 - rates.DiscountManagement)
	discountDetails["利润"] = st2.Profit * (1 - rates.DiscountProfit)

	// 获取税率
	vatRate := config.Get().DesignConfig.VatRate

	// 下浮后建筑安装工程费
	totalDiscount := 0.0
	totalDiscountTax := 0.0

	for _, v := range discountDetails {
		totalDiscount += v
		totalDiscountTax += v * vatRate
	}
	finalConstructionCost := st2.ConstructionCost - totalDiscount
	// logger.Infof("finalConstructionCost: %v ConstructionCost: %v totalDiscount: %v", finalConstructionCost, st2.ConstructionCost, totalDiscount)

	// 下浮后增值税（按9%重新计算，或按比例调整）
	finalTax := st2.Tax + t5.OtherTax - totalDiscountTax

	finalTotalWithTax := finalConstructionCost + t5.OtherFee + finalTax

	// --- 3. 支付与固定资产 ---
	paymentToBuilder := finalTotalWithTax - t4.MaterialSupply
	fixedAssetsTotal := t4.MaterialSupply + paymentToBuilder

	resume.LaborCost = paymentToBuilder
	resume.FixedAsset = fixedAssetsTotal

	return resume, nil
}

// GetMaterialPrice 获取材料价格（读取供应链数据，预算读取采购成本，结算读取结存成本）
func (s *designServiceImpl) GetMaterialPrice(materialprices []models.MaterialPrice, orgcode string, dtype int) (int, error) {
	org, err := s.userDao.GetScmOrg(orgcode)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-GetMaterialPrice",
			"org_code":    orgcode,
			"design_type": dtype,
		}).Error("获取供应链建设单位失败")
		return 0, fmt.Errorf("获取供应链建设单位失败: %v", err)
	}
	var pkorg string
	var pricecount int

	if dtype == models.DesignType_Budget {
		// 预算价格
		pricecount, err = s.scmDao.GetMaterialPurchasePrice(materialprices)
		if err != nil {
			logger.WithFields(map[string]interface{}{
				"layer":       "service",
				"operation":   "designServiceImpl-GetMaterialPrice",
				"org_code":    orgcode,
				"design_type": dtype,
			}).Error("获取项目材料采购成本失败")
			return 0, fmt.Errorf("获取项目材料采购成本失败: %v", err)
		}
	}
	if dtype == models.DesignType_Settlement {
		pkorg = org.PkorgRealLib // 结算价格，pkorg为最新结存表组织键值
		pricecount, err = s.scmDao.GetMaterialBalancePrice(pkorg, materialprices)
		if err != nil {
			logger.WithFields(map[string]interface{}{
				"layer":       "service",
				"operation":   "designServiceImpl-GetMaterialPrice",
				"org_code":    orgcode,
				"design_type": dtype,
			}).Error("获取项目材料结存成本失败")
			return 0, fmt.Errorf("获取项目材料结存成本失败: %v", err)
		}
	}
	// if dtype == daos.DesignType_Audit {
	// 	// 审核价格
	// 	pricecount, err = s.scmDao.GetMaterialAuditPrice(materialprices)
	// 	if err != nil {
	// 		logger.WithFields(map[string]interface{}{
	// 			"layer":       "service",
	// 			"operation":   "GetMaterialPrice",
	// 			"org_code":    orgcode,
	// 			"design_type": dtype,
	// 		}).Error("获取项目材料审核成本失败")
	// 		return 0, fmt.Errorf("failed to get material price: %v", err)
	// 	}
	// }

	return pricecount, nil
}

// GetProjectList 获取项目列表
func (s *designServiceImpl) GetProjectList(orgcode string, dtype int) ([]models.WebProjectList, error) {
	var projectlist []models.WebProjectList

	prjCodeList, err := s.designDao.GetDesignCodeList(orgcode, dtype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-GetProjectList",
			"org_code":    orgcode,
			"design_type": dtype,
		}).Error("获取项目列表失败")
		return nil, fmt.Errorf("获取项目列表失败: %v", err)
	}

	for _, item := range prjCodeList {
		prj, err := s.GetProjectResume(item, dtype)
		if err != nil {
			logger.WithFields(map[string]interface{}{
				"layer":       "service",
				"operation":   "designServiceImpl-GetProjectList",
				"org_code":    orgcode,
				"design_type": dtype,
			}).Error("获取项目详情失败")
			return nil, fmt.Errorf("获取项目详情失败: %v", err)
		}
		projectlist = append(projectlist, models.WebProjectList{
			ID:            prj.ID,
			DesignCode:    prj.DesignCode,
			DesignType:    dtype,
			ProjectName:   prj.Name,
			ProjectStatus: 0,
			MoneyLabor:    prj.LaborCost,
			MoneyMaterial: prj.MaterialAmount,
			Filed:         prj.Filed,
		})
	}

	return projectlist, nil
}

// LoadProjectLabor 加载项目人工条目信息
func (s *designServiceImpl) LoadProjectLabor(pcode string, dtype int) ([]models.WebProjectLaborItem, error) {
	var laborlist []models.WebProjectLaborItem
	laborlist, err := s.designDao.GetLaborList(pcode, dtype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":        "service",
			"operation":    "designServiceImpl-LoadProjectLabor",
			"project_code": pcode,
			"design_type":  dtype,
		}).Error("获取项目人工条目失败")
		return nil, fmt.Errorf("获取项目人工条目失败: %v", err)
	}
	for i := range laborlist {
		conversions, err := s.designDao.GetConversionList(laborlist[i].LID)
		if err != nil {
			logger.WithFields(map[string]interface{}{
				"layer":        "service",
				"operation":    "designServiceImpl-LoadProjectLabor",
				"project_code": pcode,
				"design_type":  dtype,
			}).Error("获取项目转换条目失败")
			return nil, fmt.Errorf("获取项目转换条目失败: %v", err)
		}
		laborlist[i].Conversions = conversions

		machines, err := s.designDao.GetMachineList(laborlist[i].LID)
		if err != nil {
			logger.WithFields(map[string]interface{}{
				"layer":        "service",
				"operation":    "designServiceImpl-LoadProjectLabor",
				"project_code": pcode,
				"design_type":  dtype,
			}).Error("获取项目机械台班条目失败")
			return nil, fmt.Errorf("获取项目机械台班条目失败: %v", err)
		}
		laborlist[i].Machines = machines

		instruments, err := s.designDao.GetInstrumentList(laborlist[i].LID)
		if err != nil {
			logger.WithFields(map[string]interface{}{
				"layer":        "service",
				"operation":    "designServiceImpl-LoadProjectLabor",
				"project_code": pcode,
				"design_type":  dtype,
			}).Error("获取项目工具仪表条目失败")
			return nil, fmt.Errorf("获取项目工具仪表条目失败: %v", err)
		}
		laborlist[i].Instruments = instruments
	}
	return laborlist, nil
}

// LoadProjectMaterial 加载项目材料条目信息
func (s *designServiceImpl) LoadProjectMaterial(pcode string, dtype int) ([]models.WebProjectMaterialItem, error) {
	var materiallist []models.WebProjectMaterialItem
	materiallist, err := s.designDao.GetMaterialList(pcode, dtype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":        "service",
			"operation":    "designServiceImpl-LoadProjectMaterial",
			"project_code": pcode,
			"design_type":  dtype,
		}).Error("获取项目材料条目失败")
		return nil, fmt.Errorf("获取项目材料条目失败: %v", err)
	}
	return materiallist, nil
}

// 计算表二数据
func (s *designServiceImpl) CalculateTable2(designcode string, dtype int) (models.SummaryTable2, error) {

	var mechanic, general float64
	var err error
	mechanic, general, err = s.calcLaborCost(designcode, dtype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":        "service",
			"operation":    "designServiceImpl-CalculateTable2",
			"project_code": designcode,
			"design_type":  dtype,
		}).Error("获取项目人工成本失败")
		return models.SummaryTable2{}, fmt.Errorf("获取项目人工成本失败: %v", err)
	}
	var machine, instrument float64

	machine, err = s.calcMachineCost(designcode, dtype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":        "service",
			"operation":    "designServiceImpl-CalculateTable2",
			"project_code": designcode,
			"design_type":  dtype,
		}).Error("获取项目机械成本失败")
		return models.SummaryTable2{}, fmt.Errorf("GetProjectMachine failed - pcode: %s, error: %v", designcode, err)
	}
	instrument, err = s.calcInstrumentCost(designcode, dtype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":        "service",
			"operation":    "designServiceImpl-CalculateTable2",
			"project_code": designcode,
			"design_type":  dtype,
		}).Error("获取项目工具仪表成本失败")
		return models.SummaryTable2{}, fmt.Errorf("获取项目工具仪表成本失败: %v", err)
	}
	var materialAmount float64

	materialAmount, _, err = s.designDao.GetMaterialCost(designcode, dtype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":        "service",
			"operation":    "designServiceImpl-CalculateTable2",
			"project_code": designcode,
			"design_type":  dtype,
		}).Error("获取项目材料成本失败")
		return models.SummaryTable2{}, fmt.Errorf("获取项目材料成本失败: %v", err)
	}

	tab2input := InputDataTab2{
		MechanicDays:     mechanic,
		GeneralDays:      general,
		MachineCost:      machine,
		InstrumentCost:   instrument,
		MainMaterialCost: materialAmount,
	}

	// 创建计算器
	tab2 := s.NewTab2(tab2input)
	// 计算（自动按依赖顺序）
	if err := tab2.CalculateTab2(); err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":        "service",
			"operation":    "designServiceImpl-CalculateTable2",
			"project_code": designcode,
			"design_type":  dtype,
		}).Error("计算项目表二失败")
		return models.SummaryTable2{}, fmt.Errorf("计算项目表二失败 - pcode: %s, error: %v", designcode, err)
	}

	st2 := models.SummaryTable2{
		ConstructionCost: tab2.items["exclusive_tax_cost"].Value,
		LaborCost:        tab2.items["labor_cost"].Value,
		MachineCost:      tab2.items["machine_cost"].Value,
		InstrumentCost:   tab2.items["instrument_cost"].Value,
		MeasureFee:       tab2.items["measure_fee"].Value,
		ManagementFee:    tab2.items["management_fee"].Value,
		Profit:           tab2.items["profit"].Value,
		Tax:              tab2.items["tax"].Value,
	}
	return st2, nil

}

// 计算表一汇总结果
func (s *designServiceImpl) CalculateBudgetSummary(designcode string, dtype int) models.SummaryTable {
	t2, err := s.CalculateTable2(designcode, dtype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":        "service",
			"operation":    "designServiceImpl-CalculateBudgetSummary",
			"project_code": designcode,
			"design_type":  dtype,
		}).Error("计算项目表二失败")
		return models.SummaryTable{}
	}

	tab5 := s.NewTab5(designcode, dtype)

	tab5.CalculateTab5(t2.ConstructionCost)
	t5 := models.SummaryTable5{
		OtherFee: tab5.Items["other_total"].ExcludingTax,
		OtherTax: tab5.Items["other_total"].VAT,
	}
	mt, _, err := s.designDao.GetMaterialCost(designcode, dtype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":        "service",
			"operation":    "designServiceImpl-CalculateBudgetSummary",
			"project_code": designcode,
			"design_type":  dtype,
		}).Error("获取项目材料成本失败")
		return models.SummaryTable{}
	}
	t4 := models.SummaryTable4{
		MaterialSupply: mt,
	}

	rates := config.Get().DesignConfig.DiscountRates

	// --- 1. 基础合计（未下浮） ---
	baseTotal := t2.ConstructionCost + t5.OtherFee
	baseTax := t2.Tax + t5.OtherTax
	baseTotalWithTax := baseTotal + baseTax

	// --- 2. 计算下浮费用 ---
	discountDetails := make(map[string]float64)
	discountDetails["人工费"] = t2.LaborCost * rates.DiscountLabor
	discountDetails["机械费"] = t2.MachineCost * rates.DiscountMachine
	discountDetails["措施费"] = t2.MeasureFee * rates.DiscountMeasure
	discountDetails["企业管理费"] = t2.ManagementFee * rates.DiscountManagement
	discountDetails["利润"] = t2.Profit * rates.DiscountProfit

	// 下浮后建筑安装工程费
	totalDiscount := 0.0
	for _, v := range discountDetails {
		totalDiscount += v
	}

	// log.Printf("totalDiscount: %f", totalDiscount)

	finalConstructionCost := t2.ConstructionCost - totalDiscount

	// 下浮后增值税（按9%重新计算，或按比例调整）
	vatRate := config.Get().DesignConfig.VatRate

	finalTax := (finalConstructionCost + t5.OtherFee) * vatRate
	finalTotalWithTax := finalConstructionCost + t5.OtherFee + finalTax

	// --- 3. 支付与固定资产 ---
	paymentToBuilder := finalTotalWithTax - t4.MaterialSupply
	fixedAssetsTotal := t4.MaterialSupply + paymentToBuilder

	return models.SummaryTable{

		BaseTotal:             baseTotal,
		BaseTax:               baseTax,
		BaseTotalWithTax:      baseTotalWithTax,
		DiscountDetails:       discountDetails,
		FinalConstructionCost: finalConstructionCost,
		FinalTax:              finalTax,
		FinalTotalWithTax:     finalTotalWithTax,
		PaymentToBuilder:      paymentToBuilder,
		FixedAssetsTotal:      fixedAssetsTotal,
	}
}

// GetConstructionCost 计算项目建筑安装工程费
func (s *designServiceImpl) GetConstructionCost(designcode string, dtype int) (float64, error) {

	var mechanic, general float64
	var err error
	mechanic, general, err = s.calcLaborCost(designcode, dtype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":        "service",
			"operation":    "designServiceImpl-GetConstructionCost",
			"project_code": designcode,
			"design_type":  dtype,
		}).Error("获取项目人工费失败")
		return 0, fmt.Errorf("获取项目人工费失败: %v", err)
	}
	var machine, instrument float64

	machine, err = s.calcMachineCost(designcode, dtype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":        "service",
			"operation":    "designServiceImpl-GetConstructionCost",
			"project_code": designcode,
			"design_type":  dtype,
		}).Error("获取项目机械费失败")
		return 0, fmt.Errorf("获取项目机械费失败: %v", err)
	}
	instrument, err = s.calcInstrumentCost(designcode, dtype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":        "service",
			"operation":    "designServiceImpl-GetConstructionCost",
			"project_code": designcode,
			"design_type":  dtype,
		}).Error("获取项目器具费失败")
		return 0, fmt.Errorf("获取项目器具费失败: %v", err)
	}
	var materialAmount float64

	materialAmount, _, err = s.designDao.GetMaterialCost(designcode, dtype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":        "service",
			"operation":    "designServiceImpl-GetConstructionCost",
			"project_code": designcode,
			"design_type":  dtype,
		}).Error("获取项目材料成本失败")
		return 0, fmt.Errorf("获取项目材料成本失败: %v", err)
	}

	tab2input := InputDataTab2{
		MechanicDays:     mechanic,
		GeneralDays:      general,
		MachineCost:      machine,
		InstrumentCost:   instrument,
		MainMaterialCost: materialAmount,
	}

	// 创建计算器
	tab2 := s.NewTab2(tab2input)
	// 计算（自动按依赖顺序）
	if err := tab2.CalculateTab2(); err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":        "service",
			"operation":    "designServiceImpl-GetConstructionCost",
			"project_code": designcode,
			"design_type":  dtype,
		}).Error("计算表二数据失败")
		return 0, fmt.Errorf("计算失败: %v", err)
	}

	cost := tab2.items["exclusive_tax_cost"].Value

	return cost, nil
}

// LoadProjectOtherFee 加载项目其他费用条目
func (s *designServiceImpl) LoadProjectOtherFee(designcode string, dtype int) (models.WebProjectOtherFee, error) {
	var err error
	var t5 models.WebProjectOtherFee

	t5.ConstructionCost, err = s.GetConstructionCost(designcode, dtype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":        "service",
			"operation":    "designServiceImpl-LoadProjectOtherFee",
			"project_code": designcode,
			"design_type":  dtype,
		}).Error("获取项目建筑安装工程费失败")
		return t5, fmt.Errorf("获取项目建筑安装工程费失败: %v", err)
	}
	t5.RateSafe = config.Get().DesignConfig.SafeRate
	t5.RateVat = config.Get().DesignConfig.VatRate
	otherfeelist, err := s.designDao.GetOtherFee(designcode, dtype)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":        "service",
			"operation":    "designServiceImpl-LoadProjectOtherFee",
			"project_code": designcode,
			"design_type":  dtype,
		}).Error("获取项目其他费用失败")
		return t5, fmt.Errorf("获取项目其他费用失败: %v", err)
	}
	for _, v := range otherfeelist {
		t5.OtherFee = append(t5.OtherFee, models.OtherFeeItem{
			Name:        v.Name,
			Basis:       v.Basis,
			TaxIncluded: v.TaxIncluded,
			Remark:      v.Remark,
		})
	}
	return t5, nil
}

// SaveProjectOtherFee 保存项目其他费用数据
func (s *designServiceImpl) SaveProjectOtherFee(dcode string, dtype int, data []models.OtherFeeItem) error {

	err := s.designDao.InTransaction(func() error {
		if len(data) == 0 {
			return s.designDao.ClearProjectOtherFee(dcode, dtype)
		}
		err := s.designDao.SetProjectOtherFee(dcode, dtype, data)
		if err != nil {
			return fmt.Errorf("设置项目其他费用失败: %w", err)
		}
		err = s.designDao.UpdateDesignTime(dcode, dtype)
		if err != nil {
			return fmt.Errorf("更新项目时间戳失败: %w", err)
		}
		return nil
	})
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":        "service",
			"operation":    "designServiceImpl-SaveProjectOtherFee",
			"project_code": dcode,
			"design_type":  dtype,
		}).Error("保存项目其他费用失败")
	} else {
		logger.WithFields(map[string]interface{}{
			"layer":        "service",
			"operation":    "designServiceImpl-SaveProjectOtherFee",
			"project_code": dcode,
			"design_type":  dtype,
		}).Info("保存项目其他费用成功")
	}
	return err
}

func (s *designServiceImpl) GetProjectReviewer(orgCode string) ([]models.ProjectReviewer, error) {
	r, err := s.userDao.GetUsersByOrg(orgCode)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":     "service",
			"operation": "designServiceImpl-GetProjectReviewer",
			"org_code":  orgCode,
		}).Error("获取项目审核人失败")
		return nil, err
	}
	var reviewers []models.ProjectReviewer
	for _, v := range r {
		reviewers = append(reviewers, models.ProjectReviewer{
			ID:   v.UserID,
			Name: v.UserName,
		})
	}
	return reviewers, nil
}

// SetProjectFiled 设置项目状态
func (s *designServiceImpl) SetProjectFiled(designCode string, state int) error {
	// 获取项目当前状态
	// stateOld, err := s.designDao.GetProjectState(designCode)
	// if err != nil {
	// 	logger.WithFields(map[string]interface{}{
	// 		"layer":         "service",
	// 		"operation":     "designServiceImpl-SetProjectState",
	// 		"project_code":  designCode,
	// 	}).Error("获取项目状态失败")
	// 	return fmt.Errorf("获取项目状态失败: %w", err)
	// }

	err := s.designDao.InTransaction(func() error {
		return s.designDao.SetProjectState(designCode, state)
	})
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":         "service",
			"operation":     "designServiceImpl-SetProjectFiled",
			"project_code":  designCode,
			"project_state": state,
		}).Error("设置项目状态失败")
		return fmt.Errorf("设置项目状态失败: %w", err)
	}

	// 此处设计为只能顺序更新项目状态，不允许撤销或跳跃
	var designTypeNew, designTypeOld int
	var strMsg string
	if state == models.ProjectState_Accept {
		designTypeOld = models.DesignType_Budget
		designTypeNew = models.DesignType_Settlement
		strMsg = "存档为结算单"
	}
	if state == models.ProjectState_Audit {
		designTypeOld = models.DesignType_Settlement
		designTypeNew = models.DesignType_Audit
		strMsg = "存档为审计单"
	}
	s.designDao.UpdateDesignTime(designCode, designTypeOld)

	// 复制人工数据
	oldLabor, err := s.LoadProjectLabor(designCode, designTypeOld)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-SetProjectFiled",
			"design_code": designCode,
		}).Warn("加载源项目人工数据失败")
		return fmt.Errorf("加载源项目人工数据失败: %w", err)
	}
	var newLabor []models.LaborItem
	for _, item := range oldLabor {
		var conversions []models.NormConversionItem
		for _, conv := range item.Conversions {
			conversions = append(conversions, models.NormConversionItem{
				NciID: conv.ID,
			})
		}
		var machines []models.MachineItem
		for _, conv := range item.Machines {
			machines = append(machines, models.MachineItem{
				MachID:   conv.ID,
				Quantity: conv.Quantity,
				Remark:   conv.Remark,
			})
		}
		var instruments []models.InstrumentItem
		for _, conv := range item.Instruments {
			instruments = append(instruments, models.InstrumentItem{
				InstID:   conv.ID,
				Quantity: conv.Quantity,
				Remark:   conv.Remark,
			})
		}
		newLabor = append(newLabor, models.LaborItem{
			DesignCode:  designCode,
			DesignType:  designTypeNew,
			Code:        item.NormItem.NormCode,
			Quantity:    item.Quantity,
			Remark:      item.Remark,
			Conversions: conversions,
			Machines:    machines,
			Instruments: instruments,
		})
	}
	err = s.SaveProjectLabor(designCode, designTypeNew, newLabor)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-SetProjectFiled",
			"design_code": designCode,
		}).Error(strMsg + "人工数据失败")
		return fmt.Errorf("%s人工数据失败: %w", strMsg, err)
	}

	// 复制材料数据
	oldMaterial, err := s.LoadProjectMaterial(designCode, designTypeOld)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-SetProjectFiled",
			"design_code": designCode,
		}).Warn("加载源项目材料数据失败")
		return fmt.Errorf("加载源项目材料数据失败: %w", err)
	}
	var newMaterial []models.MaterialItem
	for _, item := range oldMaterial {
		newMaterial = append(newMaterial, models.MaterialItem{
			DesignCode: designCode,
			DesignType: designTypeNew,
			Code:       item.Code,
			Name:       item.Name,
			Price:      item.Price,
			Quantity:   item.Quantity,
			Remark:     item.Remark,
		})
	}
	err = s.SaveProjectMaterial(designCode, designTypeNew, newMaterial, true)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-SetProjectFiled",
			"design_code": designCode,
		}).Error(strMsg + "材料数据失败")
		return fmt.Errorf("%s材料数据失败: %w", strMsg, err)
	}

	// 复制其他费用数据
	oldOther, err := s.LoadProjectOtherFee(designCode, designTypeOld)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-SetProjectFiled",
			"design_code": designCode,
		}).Warn("加载源项目其他费用失败")
		return fmt.Errorf("加载源项目其他费用失败: %w", err)
	}
	err = s.SaveProjectOtherFee(designCode, designTypeNew, oldOther.OtherFee)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-SetProjectFiled",
			"design_code": designCode,
		}).Error(strMsg + "其他费用数据失败")

		return fmt.Errorf("%s其他费用数据失败: %w", strMsg, err)
	}
	return nil
}

func (s *designServiceImpl) DeleteProject(designCode string, designType int) error {
	var err error
	isEmpty := true
	err = s.designDao.InTransaction(func() error {
		for i := len(models.DesignTypes) - 1; i > designType; i-- {
			dt := models.DesignTypes[i]
			if designType != models.DesignType_All {
				isEmpty, err = s.isProjectEmpty(designCode, i)
				if err != nil {
					return fmt.Errorf("检查项目%s是否为空失败: %w", dt, err)
				}
				if !isEmpty {
					return fmt.Errorf("请先删除项目%s数据！", dt)
				}
				if isEmpty && designType == i {
					err = s.deleteProjectData(designCode, designType)
					return err
				}
			} else {
				err = s.deleteProjectData(designCode, i)
				if err != nil {
					return fmt.Errorf("删除项目%s数据失败: %w", dt, err)
				}
			}
		}

		err = s.deleteProjectData(designCode, designType)
		if err != nil {
			return fmt.Errorf("删除项目%s数据失败: %w", designCode, err)
		}

		if designType <= models.DesignType_Budget {
			err = s.deleteProjectBase(designCode)
			if err != nil {
				return fmt.Errorf("删除项目基本信息失败: %w", err)
			}
		}
		return nil
	})
	if err != nil {
		return fmt.Errorf("删除项目%s数据失败: %w", designCode, err)
	}
	return nil
}

func (s *designServiceImpl) isProjectEmpty(designCode string, designType int) (bool, error) {
	dtName := models.DesignTypes[designType]
	hasLabor, err := s.designDao.GetLaborList(designCode, designType)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-DeleteProjectBase",
			"design_code": designCode,
		}).Error("检查项目" + dtName + "人工数据失败")
		return false, fmt.Errorf("检查项目%s人工数据失败: %w", dtName, err)
	}
	if len(hasLabor) > 0 {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-DeleteProjectBase",
			"design_code": designCode,
		}).Error("项目仍有" + dtName + "人工数据，不能删除")
		return false, fmt.Errorf("项目仍有%s人工数据，不能删除项目信息", dtName)
	}

	hasMaterial, err := s.designDao.GetMaterialList(designCode, designType)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-DeleteProjectBase",
			"design_code": designCode,
		}).Error("检查项目" + dtName + "材料数据失败")
		return false, fmt.Errorf("检查项目%s材料数据失败: %w", dtName, err)
	}
	if len(hasMaterial) > 0 {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-DeleteProjectBase",
			"design_code": designCode,
		}).Error("项目仍有" + dtName + "材料数据，不能删除")
		return false, fmt.Errorf("项目仍有%s材料数据，不能删除项目信息", dtName)
	}
	return true, nil

}

func (s *designServiceImpl) deleteProjectBase(designCode string) error {

	err := s.designDao.DeleteProjectBase(designCode)
	if err != nil {
		logger.WithFields(map[string]interface{}{
			"layer":       "service",
			"operation":   "designServiceImpl-deleteProjectBase",
			"design_code": designCode,
		}).Error("删除项目基本信息失败")
		return fmt.Errorf("删除项目基本信息失败: %w", err)
	}
	return nil
}

func (s *designServiceImpl) deleteProjectData(designCode string, designType int) error {
	var err error

	if designType == models.DesignType_All {
		return nil
	}
	err = s.designDao.ClearProjectLabors(designCode, designType)
	if err != nil {
		return fmt.Errorf("删除项目%s人工数据失败: %w", models.DesignTypes[designType], err)
	}

	err = s.designDao.ClearProjectMaterials(designCode, designType)
	if err != nil {
		return fmt.Errorf("删除项目%s材料数据失败: %w", models.DesignTypes[designType], err)
	}
	err = s.designDao.ClearProjectOtherFee(designCode, designType)
	if err != nil {
		return fmt.Errorf("删除项目%s其他费用数据失败: %w", models.DesignTypes[designType], err)
	}
	if designType > models.DesignType_Budget {
		err = s.designDao.SetProjectState(designCode, designType-1)
		if err != nil {
			return fmt.Errorf("设置项目状态失败: %w", err)
		}
	}
	return nil
}

func (s *designServiceImpl) calcLaborCost(pcode string, dtype int) (float64, float64, error) {
	labors, err := s.designDao.GetLaborCost(pcode, dtype)
	if err != nil {
		return 0, 0, fmt.Errorf("获取项目人工成本失败: %w", err)
	}
	var mechanicCost float64
	var generalCost float64
	for _, l := range labors {
		mechanicCost += l.Mechanic * l.Quantity
		generalCost += l.General * l.Quantity
	}
	return mechanicCost, generalCost, nil
}

func (s *designServiceImpl) calcMachineCost(pcode string, dtype int) (float64, error) {
	machines, err := s.designDao.GetMachineCost(pcode, dtype)
	if err != nil {
		return 0, fmt.Errorf("获取项目机械成本失败: %w", err)
	}
	var machineCost float64
	for _, m := range machines {
		machineCost += m.Machine
	}
	return machineCost, nil
}

func (s *designServiceImpl) calcInstrumentCost(pcode string, dtype int) (float64, error) {
	instruments, err := s.designDao.GetInstrumentCost(pcode, dtype)
	if err != nil {
		return 0, fmt.Errorf("获取项目仪器仪表成本失败: %w", err)
	}
	var instrumentCost float64
	for _, i := range instruments {
		instrumentCost += i.Instrument
	}
	return instrumentCost, nil
}
